package cn.xzqwjw.taskmanager.config;

import cn.xzqwjw.taskmanager.common.interceptor.WebInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.http.converter.BufferedImageHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.*;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * 自定义配置中心
 *
 * @author wjw
 */
@Configuration
@Slf4j
public class WebConfig implements WebMvcConfigurer {

  /**
   * 加载自定义拦截器
   */
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    // 配置白名单
    List<String> whiteList = new ArrayList<>();
    whiteList.add("/favicon.ico");
    whiteList.add("/static/**");
    whiteList.add("/error/**");
    // 拦截所有请求，排除白名单里的 url
    registry.addInterceptor(new WebInterceptor())
        .addPathPatterns("/**")
        .excludePathPatterns(whiteList);
  }

  /**
   * 所有请求都允许跨域，使用这种配置就不需要在interceptor中配置header了
   */
  @Override
  public void addCorsMappings(CorsRegistry registry) {
    // 设置允许跨域的路由
    registry.addMapping("/**")
        // 允许访问的头信息， * 表示全部
        .allowedHeaders("*")
        .exposedHeaders("authorization")
        // 是否允许证书（cookies）跨域
        .allowCredentials(true)
        // 当 allowCredentials 为 true, allowedOrigins 不能包含特殊的值"*"
        // 因为它不能设置 Access-Control-Allow-Origin 响应头
        // 为允许 cookie ，应准确的列出允许的域名，或使用 allowedOriginPatterns
        // .allowedOrigins("*")
        // .allowedOrigins("http://localhost:9050")
        // 设置允许跨域请求的域名
        // 允许向该服务器提交请求的URI，*表示全部允许。
        // 这里尽量限制来源域，比如 http://xxxx:8080 ,以降低安全风险。
        .allowedOriginPatterns("*")
        // .allowedOriginPatterns("http://localhost:8082")
        // 设置允许的方法
        // 允许提交请求的方法，*表示全部允许，也可以单独设置GET、PUT等
        .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")
        // .allowedMethods("*")
        // 跨域允许时间 1小时=3600秒*24小时=86400秒
        // 预检请求的缓存时间（秒），即在这个时间段里，对于相同的跨域请求不会再预检了
        .maxAge(86400);
  }

  /**
   * 增加图片、时间转换器
   *
   * @param converters 转换器
   */
  @Override
  public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    // 增加图片转换器
    converters.add(new BufferedImageHttpMessageConverter());
  }

  // 用@value标签直接读取yml文件中的配置
  @Value("${custom-option.upload-root-dir}")
  private String uploadRootPath;

  /**
   * 配置静态资源路径，先添加的优先级高于后添加的
   */
  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    // 将所有 /static/** 访问都映射到 classpath:/static/ 目录下
    // 这里设置了，还需要再 security config 文件中放开这个目录的访问权限
    registry.addResourceHandler("/static/**")
        .addResourceLocations("classpath:/static/");
    // addResourceHandler 是设置你想在url请求的路径
    // addResourceLocations 是设置上传文件存放的物理真实路径
    // 使用方式：启动项目，访问的 ip:端口/项目基本路径/upload-file/12345.jpg 即可查看图片
    registry.addResourceHandler("/upload-file/**")
        .addResourceLocations("file:" + uploadRootPath);
    // 也可以支持路径嵌套，在 upload-file 文件夹中在创建子目录，访问的时候加上即可
    // 可以自定义资源处理类，对加载后的资源进行二次处理，比如图片统一打标识、解密之类的
    //.resourceChain(true).addTransformer(new SecretImageResourceTransformerSupport());
  }

}
